use std::error::Error;
use crate::evidence::ITrusteeEvidence;
use async_trait::async_trait;
use once_cell::sync::Lazy;
use plugin_manager::{PluginBase, PluginError, ServiceHostFunctions, ServicePlugin};
use serde_json::Value;

pub struct ItrusteePlugin {
    plugin_type: String,
    service_host_functions: ServiceHostFunctions,
}

impl ItrusteePlugin {
    pub fn new(plugin_type: String, service_host_functions: ServiceHostFunctions) -> Self {
        Self { plugin_type, service_host_functions }
    }
}

impl PluginBase for ItrusteePlugin {
    fn plugin_type(&self) -> &str {
        self.plugin_type.as_str()
    }
}

#[async_trait]
impl ServicePlugin for ItrusteePlugin {
    fn get_sample_output(&self) -> Value {
        SAMPLE_OUTPUT.clone()
    }

    async fn verify_evidence(
        &self,
        user_id: &str,
        node_id: Option<&str>,
        evidence: &Value,
        nonce: Option<&[u8]>,
    ) -> Result<Value, PluginError> {
        let mut evidence_value = ITrusteeEvidence::from_json_value(evidence)?;
        let result = evidence_value.verify(user_id, node_id, nonce, self).await?;
        Ok(result)
    }
}
static SAMPLE_OUTPUT: Lazy<Value> = Lazy::new(|| {
    serde_json::from_str(
        r#"{
              "report_sign": {
                "sce_no_as": "XXX"
              },
              "akcert": {
                "sce_no_as": {
                  "signature": {
                    "drk_cert": "XXX",
                    "drk_sign": "XXX"
                  },
                  "payload": {
                    "version": "TEE.RA.1.0",
                    "timestamp": "4444926305947760",
                    "scenario": "sce_no_as",
                    "sign_alg": "PS256",
                    "hash_alg": "HS256",
                    "qta_img": "CuF2-M1v-lH7SOx4eWUwDCsns5PtUZol724CyLYTkok",
                    "qta_mem": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
                    "tcb": "",
                    "ak_pub": {
                      "kty": "RSA",
                      "n": "XXX",
                      "e": "AQAB"
                    }
                  },
                  "handler": "provisioning-output"
                }
              },
              "payload": {
                "version": "TEE.RA.1.0",
                "timestamp": "4444943281849874",
                "nonce": "f9f0ef48asdasdss",
                "key": {
                  "pub_key": {
                    "n": "XXX",
                    "e": "AQAB",
                    "kty": "RSA"
                  },
                  "enc_key": "XXX"
                },
                "scenario": "sce_no_as",
                "uuid": "4f84c0e0-4c3f-422f-97dc-14bfa2314ad1",
                "requester_uuid": "",
                "hash_alg": "HS256",
                "sign_alg": "PS256",
                "ta_mem": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
                "ta_img": "jEPn8PTkovDQBW0BjWWCM4JWpp6BIIHEnYJN7zJQM7U",
                "ta_attr": "",
                "tcb": ""
              },
              "handler": "report-output"
        }"#,
    )
    .unwrap()
});

#[no_mangle]
pub fn create_plugin(host_functions: ServiceHostFunctions, plugin_type: &str) -> Result<Box<dyn ServicePlugin>, Box<dyn Error>> {
    if plugin_type != "itrustee" {
        return Err(Box::new(PluginError::InputError("Invalid plugin type".to_string())));
    }
    Ok(Box::new(ItrusteePlugin::new(plugin_type.to_string(), host_functions)))
}
